/*
    translation blocks options
    Copyright (C) 2011  Jiabo <jiabo2011@gmail.com>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/mman.h>

#include "../global.h"
#include "tb.h"

//#define DEBUG_TB

#ifdef DEBUG_TB
#define DPRINTF(fmt, ...)                                       \
    do { printf("TB: " fmt , ## __VA_ARGS__); } while (0)
#else
#define DPRINTF(fmt, ...)
#endif

#define MAX_TB_NUMS	1000

static TranslationBlock *tbs;
static int nb_tbs;
static uint32_t *code_gen_buffer;
static uint32_t *code_gen_ptr;


TranslationBlock *tb_alloc(uint32_t s_pc)
{
	TranslationBlock *tb;

	if (nb_tbs >= MAX_TB_NUMS)
		return NULL;
	tb = &tbs[nb_tbs++];
	tb->source_pc = s_pc;
	tb->code_buf = code_gen_ptr;

	if (debug_stop)
	printf("%s: tb %d, buf offset: %08x\n", __func__, nb_tbs,
		(code_gen_ptr - code_gen_buffer) * 4);
	return tb;
}

void tb_set_offset(uint32_t offset)
{
	code_gen_ptr += offset;
}

TranslationBlock *tb_find(uint32_t s_pc)
{
	TranslationBlock *tb;
	int i = 0;

	for (tb = tbs; i < nb_tbs; i++) {
		if (tb->source_pc == s_pc) {
			DPRINTF("%s: buf offset: %08x\n", __func__,
				(code_gen_ptr - code_gen_buffer) * 4);
			return tb;
		}
		tb++;
	}
	DPRINTF("no tb found\n");

	return NULL;
}

void tb_flush(void)
{
	nb_tbs = 0;
	code_gen_ptr = code_gen_buffer;
}

void tb_init(void)
{
	tbs = calloc(MAX_TB_NUMS, sizeof(TranslationBlock));

	code_gen_buffer = mmap(NULL, 4 * 1024 * 1024,
		PROT_WRITE | PROT_READ | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
	if (code_gen_buffer == MAP_FAILED) {
		fprintf(stderr, "Could not allocate dynamic translator buffer\n");
		exit(-1);
	}
//	printf("alloc code buffer at %p\n", code_gen_buffer);
	tb_flush();
}

void tb_exit(void)
{
	free(tbs);
}

